=begin rdoc
Unit tests for eventset class.

Author::    Matthias Woehrle  (mailto:matthias.woehrle@tik.ee.ethz.ch)
Copyright:: Copyright (c) 2008 ETH Zurich
License::   

TODO:

MISSING:
* Test for to_s function

COMMENTS:

In these test cases we have deal with sets, where we cannot predict the ordering.
The same is true for permutation for the array. That is why we do not compare
  the actual objects, but rather we unshift from the objects and check that individual 
  items are included. If we additionally check, that after the unshift operation, there
  are no more elements in the result we verify the match iterative. Thus we have test cases
  with multiple assertions which just represent a single assertion of equality.
=end



$:.unshift File.join(File.dirname(__FILE__), "..", "lib")

require 'EventSet'
require 'test/unit'

class TestEventSetPrimitive < Test::Unit::TestCase
  def setup
    @e  = EventSet.new()
    @f  = EventSet.new()
    @e1 = Event.new(:nodeid => 3, :type => :send, :origin=> 1)
    @e2 = Event.new(:nodeid => 3, :type => :send, :origin=> 2)
    @e3 = Event.new(:nodeid => 3, :type => :send, :origin=> 3)
    @e4 = Event.new(:nodeid => 3, :type => :send, :origin=> 4)
    @e5 = Event.new(:nodeid => 3, :type => :receive, :origin=> 1)
    @e6 = Event.new(:nodeid => 4, :type => :receive, :origin=> 1)
    @e7 = Event.new(:nodeid => 5, :type => :meas, :origin=> 3, :temp=>12)
    @e8 = Event.new(:nodeid => 6, :type => :meas, :origin=> 7, :humidity=>0.9)
  end
  
  #add same event to the event sets, so they are still the same
   def test_add_should_return_equal_sets
     @e.add(@e1)
     @f.add(@e1)
     assert_equal(@e, @f)
   end

   #add an already included event does not work - deprecated due to speed - assume clean logs
#    def test_add_should_return_set_also_when_adding_duplicate_events
#      @e.add(@e1)
#      @f.add(@e1)
#      @f.add(@e1)
#      assert_equal(@e, @f)
#    end

    #add two different events, and the length of the set must be two
     def test_add_should_return_the_right_cardinality_for_the_set
       @f.add(@e1)
       @f.add(@e2)
       assert_equal(2,@f.length())
     end

   
   #test for union of sets
   def test_union_should_return_the_union
     g  = EventSet.new()
     @e.add(@e1)
     @f.add(@e2)
     g = @e.union(@f)
     @e.add(@e2)
     assert_equal(@e,g)
   end

   #test for intersection of sets   
   def test_intersection_should_return_the_events_in_both_sets
     g = EventSet.new()
     h = EventSet.new()
     @e.add(@e1)
     @f.add(@e1)     
     @f.add(@e2)
     g = @e.intersection(@f)
     h.add(@e1)
     assert_equal(h,g)
   end     

   #test for intersection of sets   
   def test_subtract_should_return_events_which_are_not_in_both_sets
     g = EventSet.new()
     h = EventSet.new()
     @e.add(@e1)
     @f.add(@e1)     
     @f.add(@e2)
     g = @f.subtract(@e)
     h.add(@e2)
     assert_equal(h,g)
   end
   
   #test the each iterator
   def test_each_should_show_that_only_a_single_unique_event_is_added_at_a_time_and_all_are_added_eventually
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     empty = EventSet.new()
     @e.each do  |event|
       g = EventSet.new()
       g.add(event)
       #This tests that only a single and novel event is added 
       #for each item, which was not included before 
       assert_equal(empty, g.intersection(@f))
       @f.add(event)
     end
     #This checks that all events were added finally
     assert_equal(@e, @f)
   end
   
   #test the clear
  def test_clear_should_return_the_empty_set
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     empty = EventSet.new()
     @e.clear
     assert_equal(empty, @e)
  end 
  
  #test for type send filtering
   def test_get_send_events_should_return_all_events_in_the_set_with_a_type_of_send
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     @f.add(@e1)
     @f.add(@e2)
     @f.add(@e3)
     @f.add(@e4)     
     filterset=@e[:type=>:send]
     assert_equal(@f, filterset)
   end

   #small tests on a single event set
   def test_get_temp_events_should_return_all_events_in_the_set_with_a_temp_key
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e7)
     @f.add(@e7)
     filterset=@e[:temp]
     assert_equal(@f, filterset)
   end

   #check that wrong matched return empty event set
   def test_get_none_events_empty_should_return_no_events_in_the_set_by_using_a_not_included_key
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e7)
     filterset=@e[:none]
     assert(filterset.empty?)
   end

   #check that wrong matched return empty event set
   def test_get_temp_events_empty_should_return_empty_set_since_no_such_events_are_included
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e7)
     filterset=@e[:temp=>13]
     assert_equal(EventSet.new, filterset)
   end

   #check that matched returns one element event set
   def test_get_temp_events_empty_should_return_specific_event_with_the_given_temp_value
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e7)
     @f.add(@e7)
     filterset=@e[:temp=>12]
     assert_equal(@f, filterset)
   end

   #check that matched returns one element event set
    def test_false_filter_should_raise_exception
      filterset = EventSet.new()
      @e.add(@e1)
      @e.add(@e2)
      @e.add(@e7)
      @f.add(@e7)
      assert_raise RuntimeError do 
        filterset=@e["temp"]
      end
    end
    
         
   #add key to all events in a set via the assignment method
  def test_add_key_should_return_all_events_when_selecting_the_new_key_since_it_was_added_before
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     @e.add_key(:notice=>'success')
     filterset=@e[:notice=>'success']
     assert_equal(@e, filterset)
  end

  def test_remove_key_should_return_no_events_when_selecting_the_removed_key_since_it_was_added_before
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     @e.remove_key(:origin)
     filterset=@e[:origin]
     assert_equal(EventSet.new, filterset)
  end
  
  def test_remove_key_should_not_change_the_number_of_events
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     @e.remove_key(:origin)
     assert_equal(8, @e.length)
  end  
  
  def test_values_integer_should_return_all_values_of_origin
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     assert_equal([1,2,3,4,7], @e.values(:origin))
  end
  
  #check that matched returns one element event set
   def test_false_values_filter_should_raise_exception
     filterset = EventSet.new()
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e7)
     @f.add(@e7)
     assert_raise Exception do 
       filterset=@e.values("temp")
     end
   end
  

  def test_values_empty_should_return_no_values_as_theres_no_seqNo
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     assert_equal([], @e.values(:seqNo))
  end

  def test_values_symbol_should_return_all_symbols_of_the_given_type
     @e.add(@e1)
     @e.add(@e2)
     @e.add(@e3)
     @e.add(@e4)
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     @e.add(@e8)
     assert_equal([:meas, :receive, :send], @e.values(:type))
  end

  #check to_s method
  #TODO : I have problems with escaped white space in the reference
  #That's why here is only a loose check
   def test_to_s_checks_that_each_individual_string_is_included_for_the_whole_set
     @e.add(@e5)
     @e.add(@e6)
     @e.add(@e7)
     assert_match(@e5.to_s, @e.to_s)
     assert_match(@e6.to_s, @e.to_s)
     assert_match(@e7.to_s, @e.to_s)
   end 

end

class TestEventSetEqual < Test::Unit::TestCase
  def setup
    @e  = EventSet.new()
    @f  = EventSet.new()
    @e1 = Event.new(:nodeid => 3, :type => :send, :origin=> 1)
    @e2 = Event.new(:nodeid => 3, :type => :send, :origin=> 2)
    @e3 = Event.new(:nodeid => 3, :type => :send, :origin=> 3)
    @e.add(@e1)  
    @e.add(@e2)  
    @e.add(@e3)                   
  end

   def test_equality_if_one_is_no_eventset
     e  = [1,2,3,4]
     assert(!@e.eql?(e))
   end

   def test_equality_if_both_are_eventsets_and_not_equal
     @f.add(@e1)  
     @f.add(@e2)  
     assert(!@e.eql?(@f))
   end  
   def test_equality_if_both_are_eventsets_and_equal
     @f.add(@e1)  
     @f.add(@e2)  
     @f.add(@e3)      
     assert(@e.eql?(@f))
   end
   
end


  
class TestArrayClone < Test::Unit::TestCase
    def setup
      @g = Array.new
      @f=EventSet.new
      @receive4 = Event.new(:nodeid => 20, :type => :receive, :origin=> 3, :destination=>20, :time => 12)
      @receive5 = Event.new(:nodeid => 20, :type => :receive, :origin=> 3, :destination=>20, :time => 13)    
      @send1_mod = Event.new(:nodeid => 3, :type => :transmission, :origin=> 3, :destination=>4)
      @f.merge([@send1_mod, @receive4, @receive5])
      @g.concat([0,2,3,@f])      
      @nilArray = [0,2,3.2342, "me",nil]
    end
    
    def test_for_array_with_nils_for_deep_clone
      a = @nilArray.deep_clone
      a[0] = 1
      assert_equal([0,2,3.2342, "me",nil], @nilArray)
    end

    def test_for_compsoed_array_for_deep_clone
      newArray = Array.new
      a = @g.deep_clone
      a[0] = 1
      newArray.concat([0,2,3,@f])
      assert_equal(newArray, @g)
    end
  
end